home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / MagPLIP / source / server.c < prev    next >
C/C++ Source or Header  |  1998-04-01  |  33KB  |  1,158 lines

  1. /*
  2. ** $VER: server.c 1.15 (01 Apr 1998)
  3. **
  4. ** magplip.device - Parallel Line Internet Protocol
  5. **
  6. ** Original code written by Oliver Wagner and Michael Balzer.
  7. **
  8. ** This version has been completely reworked by Marius Gröger, introducing
  9. ** slight protocol changes. The new source is a lot better organized and
  10. ** maintainable.
  11. **
  12. ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
  13. ** The new source is significantly faster and yet better maintainable.
  14. **
  15. ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
  16. ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
  17. ** (C) Copyright 1995-1996 Marius Gröger
  18. **     All Rights Reserved
  19. **
  20. ** $HISTORY:
  21. **
  22. ** 01 Apr 1998 : 001.015 :  integrated modifications for linPLIP from Stephane
  23. ** 19 Mar 1998 : 001.014 :  fixed S2_ONLINE bug, which returned an
  24. **                          error by a call to go online if it was
  25. **                          already online. Report from Holger Kruse.
  26. **                          Fixed by Stefan Ruppert.
  27. ** 29 Mar 1996 : 001.014 :  changed copyright note
  28. ** 24 Feb 1996 : 001.013 :  added PRTRSEL data direction signal
  29. ** 30 Dec 1995 : 001.012 :  + dynamic allocation of only one frame buffer
  30. **                          PLIP_MAXMTU now 128k
  31. **                          + a bad MTU setting in ENV: will be
  32. **                          forced to PLIP_MAXMTU instead of PLIP_DEFMTU
  33. **                          + server task acknowledge now after calling
  34. **                          readargs to avoid inconsistencies
  35. ** 03 Sep 1995 : 001.011 :  hardware addressing nicer
  36. ** 30 Aug 1995 : 001.010 :  + support for timer-timed timeout :-)
  37. **                          + minor declaration related changes
  38. ** 20 Aug 1995 : 001.009 :  support for ASM xfer routines
  39. **                          removed obsolete CIA macros (mag/jk/mm)
  40. ** 29 Jul 1995 : 001.008 :  support for arbitration delay
  41. **                          symmetrical handling
  42. ** 26 Apr 1995 : 001.007 :  _very_ nasty bug would miss packets and get
  43. **                          the driver totally irritated
  44. ** 25 Apr 1995 : 001.006 :  now compiles with ANSI and STRICT
  45. **                          fixed bug with resource allocation
  46. ** 08 Mar 1995 : 001.005 :  write req. are now handled by device.c
  47. ** 06 Mar 1995 : 001.004 :  collision delay added
  48. ** 06 Mar 1995 : 001.003 :  hardware transmission errors are no longer retried
  49. **                          because this is any upper layers job
  50. ** 04 Mar 1995 : 001.002 :  event tracking *much* more conform to SANA-2
  51. ** 18 Feb 1995 : 001.001 :  startup now a bit nicer
  52. **                          using BASEPTR
  53. ** 12 Feb 1995 : 001.000 :  reworked original
  54. */
  55.  
  56. #define DEBUG 0
  57.  
  58. /*F*/ /* includes */
  59. #ifndef CLIB_EXEC_PROTOS_H
  60. #include <clib/exec_protos.h>
  61. #include <pragmas/exec_sysbase_pragmas.h>
  62. #endif
  63. #ifndef CLIB_DOS_PROTOS_H
  64. #include <clib/dos_protos.h>
  65. #include <pragmas/dos_pragmas.h>
  66. #endif
  67. #ifndef CLIB_CIA_PROTOS_H
  68. #include <clib/cia_protos.h>
  69. #include <pragmas/cia_pragmas.h>
  70. #endif
  71. #ifndef CLIB_MISC_PROTOS_H
  72. #include <clib/misc_protos.h>
  73. #include <pragmas/misc_pragmas.h>
  74. #endif
  75. #ifndef CLIB_TIME_PROTOS_H
  76. #include <clib/timer_protos.h>
  77. #include <pragmas/timer_pragmas.h>
  78. #endif
  79. #ifndef CLIB_UTILITY_PROTOS_H
  80. #include <clib/utility_protos.h>
  81. #include <pragmas/utility_pragmas.h>
  82. #endif
  83.  
  84. #ifndef EXEC_MEMORY_H
  85. #include <exec/memory.h>
  86. #endif
  87. #ifndef EXEC_INTERRUPTS_H
  88. #include <exec/interrupts.h>
  89. #endif
  90. #ifndef EXEC_DEVICES_H
  91. #include <exec/devices.h>
  92. #endif
  93. #ifndef EXEC_IO_H
  94. #include <exec/io.h>
  95. #endif
  96.  
  97. #ifndef DEVICES_SANA2_H
  98. #include <devices/sana2.h>
  99. #endif
  100.  
  101. #ifndef HARDWARE_CIA_H
  102. #include <hardware/cia.h>
  103. #endif
  104.  
  105. #ifndef RESOURCES_MISC_H
  106. #include <resources/misc.h>
  107. #endif
  108.  
  109. #ifndef _STRING_H
  110. #include <string.h>
  111. #endif
  112.  
  113. #ifndef __MAGPLIP_H
  114. #include "magplip.h"
  115. #endif
  116. #ifndef __DEBUG_H
  117. #include "debug.h"
  118. #endif
  119. #ifndef __COMPILER_H
  120. #include "compiler.h"
  121. #endif
  122. /*E*/
  123.  
  124. /*F*/ /* defines, types and enums */
  125.  
  126.    /*
  127.    ** return codes for arbitratedwrite()
  128.    */
  129. typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
  130.  
  131.    /* return val, cut to min or max if exceeding range */
  132. #define BOUNDS(val, min, max) ((val) <= (max) ? ((val) >= (min) ? (val) :\
  133.                              (min)) : (max))
  134.  
  135. /*E*/
  136. /*F*/ /* imports */
  137.    /* external functions */
  138. GLOBAL VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
  139. GLOBAL VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
  140. GLOBAL USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
  141. GLOBAL BOOL ASM hwsend(REG(a0) BASEPTR);
  142. GLOBAL BOOL ASM hwrecv(REG(a0) BASEPTR);
  143. GLOBAL VOID ASM interrupt(REG(a1) BASEPTR);
  144.  
  145.    /* amiga.lib provides for these symbols */
  146. GLOBAL FAR volatile struct CIA ciaa,ciab;
  147. /*E*/
  148. /*F*/ /* exports */
  149. PUBLIC VOID SAVEDS ServerTask(void);
  150. /*E*/
  151. /*F*/ /* private */
  152. PRIVATE struct PLIPBase *startup(void);
  153. PRIVATE REGARGS VOID DoEvent(BASEPTR, long event);
  154. PRIVATE VOID readargs(BASEPTR);
  155. PRIVATE BOOL init(BASEPTR);
  156. PRIVATE BOOL hwattach(BASEPTR);
  157. PRIVATE VOID hwdetach(BASEPTR);
  158. PRIVATE REGARGS BOOL goonline(BASEPTR);
  159. PRIVATE REGARGS VOID gooffline(BASEPTR);
  160. PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
  161. PRIVATE REGARGS VOID dowritereqs(BASEPTR);
  162. PRIVATE REGARGS VOID doreadreqs(BASEPTR);
  163. PRIVATE REGARGS VOID dos2reqs(BASEPTR);
  164. /*E*/
  165.  
  166. /*F*/ /* CIA access macros & functions */
  167.  
  168. #define CLEARINT        SetICR(CIAABase, CIAICRF_FLG)
  169. #define DISABLEINT      AbleICR(CIAABase, CIAICRF_FLG)
  170. #define ENABLEINT       AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
  171.  
  172. #ifdef LINPLIP
  173.  
  174. /* Most of these defines have no meaning at all, but it's safe ... */
  175. #  define SETCIAOUTPUT
  176. #  define SETCIAINPUT
  177. #  define PARINIT(b)      ciaa.ciaddrb = 0xff; ciaa.ciaprb = 0x00
  178.  
  179. /* Good line : SELECT=POUT=PUSY=0 */
  180. #  define TESTLINE(b)     ((ciab.ciapra&(CIAF_PRTRSEL|CIAF_PRTRPOUT|CIAF_PRTRBUSY)) || pb->pb_Flags&PLIPF_RECEIVING)
  181. #  define SETREQUEST(b)
  182. #  define CLEARREQUEST(b)
  183.  
  184. #else
  185.  
  186. #  define SETCIAOUTPUT    ciab.ciapra |= CIAF_PRTRSEL; ciaa.ciaddrb = 0xFF
  187. #  define SETCIAINPUT     ciab.ciapra &= ~CIAF_PRTRSEL; ciaa.ciaddrb = 0x00
  188. #  define PARINIT(b)      SETCIAINPUT;                                       \
  189.             ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
  190.             ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
  191.  
  192. #  define TESTLINE(b)     (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
  193. #  define SETREQUEST(b)   ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
  194. #  define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
  195.  
  196. #endif
  197.  
  198. /*E*/
  199.  
  200.    /*
  201.    ** functions to gain/release hardware, initialise communication
  202.    ** and for xmission timeout handling
  203.    */
  204. /*F*/ PRIVATE BOOL hwattach(BASEPTR)
  205. {
  206.    BOOL rc = FALSE;
  207.  
  208.    d(("entered\n"));
  209.  
  210.    if (MiscBase = OpenResource("misc.resource"))
  211.    {
  212.       if (CIAABase = OpenResource("ciaa.resource"))
  213.       {
  214.      CiaBase = CIAABase;
  215.  
  216.      d(("ciabase is %lx\n",CiaBase));
  217.  
  218.      /* obtain exclusive access to the parallel hardware */
  219.      if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
  220.      {
  221.         pb->pb_AllocFlags |= 1;
  222.         if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
  223.         {
  224.            pb->pb_AllocFlags |= 2;
  225.  
  226.            /* Add our interrupt to handle CIAICRB_FLG.
  227.            ** This is also cia.resource means of granting exclusive
  228.            ** access to the related registers in the CIAs.
  229.            */
  230.            pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  231.            pb->pb_Interrupt.is_Node.ln_Pri  = 127;
  232.            pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
  233.            pb->pb_Interrupt.is_Data         = (APTR)pb;
  234.            pb->pb_Interrupt.is_Code         = (VOID (*)())&interrupt;
  235.  
  236.            /* We must Disable() bcos there could be an interrupt already
  237.            ** waiting for us. We may, however, not Able/SetICR() before
  238.            ** we have access!
  239.            */
  240.            Disable();
  241.            if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
  242.            {
  243.           DISABLEINT;                       /* this is what I meant */
  244.           rc = TRUE;
  245.            }
  246.            Enable();
  247.  
  248.            if (rc)
  249.            {
  250.           pb->pb_AllocFlags |= 4;
  251.           PARINIT(pb);    /* cia to input, handshake in/out setting */
  252.           CLEARREQUEST(pb);                /* setup handshake lines */
  253.           CLEARINT;                         /* clear this interrupt */
  254.           ENABLEINT;                            /* allow interrupts */
  255.            }
  256.  
  257.         }
  258.         else
  259.            d(("no parallelbits\n"));
  260.      }
  261.      else
  262.         d(("no parallelport\n"));
  263.       }
  264.       else
  265.      d(("no misc resource\n"));
  266.    }
  267.    else
  268.       d(("no misc resource\n"));
  269.  
  270.    return rc;
  271. }
  272. /*E*/
  273. /*F*/ PRIVATE VOID hwdetach(BASEPTR)
  274. {
  275.    if (pb->pb_AllocFlags & 4)
  276.    {
  277.       DISABLEINT;
  278.       CLEARINT;
  279.       RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
  280.    }
  281.  
  282.    if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
  283.  
  284.    if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
  285.  
  286.    pb->pb_AllocFlags = 0;
  287. }
  288. /*E*/
  289. /*F*/ PRIVATE ULONG ASM SAVEDS exceptcode(REG(d0) ULONG sigmask, REG(a1) BASEPTR)
  290. {
  291.    /*extern void KPrintF(char *,...);
  292.    KPrintF("exceptcode\n");*/
  293.  
  294.    /* remove the I/O Block from the port */
  295.    WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  296.  
  297.    /* this tells the xfer routines to cease polling */
  298.    pb->pb_TimeoutSet = 0xff;
  299.  
  300.    return sigmask;            /* re-enable the signal */
  301. }
  302. /*E*/
  303.  
  304.    /*
  305.    ** functions to go online/offline
  306.    */
  307. /*F*/ PRIVATE REGARGS VOID rejectpackets(BASEPTR)
  308. {
  309.    struct IOSana2Req *ios2;
  310.  
  311.    ObtainSemaphore(&pb->pb_WriteListSem);
  312.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
  313.    {
  314.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  315.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  316.       DevTermIO(pb,ios2);
  317.    }
  318.    ReleaseSemaphore(&pb->pb_WriteListSem);
  319.  
  320.    ObtainSemaphore(&pb->pb_ReadListSem);
  321.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
  322.    {
  323.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  324.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  325.       DevTermIO(pb,ios2);
  326.    }
  327.    ReleaseSemaphore(&pb->pb_ReadListSem);
  328.  
  329.    ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  330.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
  331.    {
  332.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  333.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  334.       DevTermIO(pb,ios2);
  335.    }
  336.    ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  337. }
  338. /*E*/
  339. /*F*/ PRIVATE REGARGS BOOL goonline(BASEPTR)
  340. {
  341.    BOOL rc = TRUE;
  342.  
  343.    d(("trying to go online\n"));
  344.  
  345.    if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  346.    {
  347.       if (!hwattach(pb))
  348.       {
  349.      d(("error going online\n"));
  350.      rc = FALSE;
  351.       }
  352.       else
  353.       {
  354.      GetSysTime(&pb->pb_DevStats.LastStart);
  355.      pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
  356.      DoEvent(pb, S2EVENT_ONLINE);
  357.      d(("i'm now online!\n"));
  358.       }
  359.    }
  360.  
  361.    return rc;
  362. }
  363. /*E*/
  364. /*F*/ PRIVATE REGARGS VOID gooffline(BASEPTR)
  365. {
  366.    if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
  367.    {
  368.       hwdetach(pb);
  369.  
  370.       pb->pb_Flags |= PLIPF_OFFLINE;
  371.  
  372.       DoEvent(pb, S2EVENT_OFFLINE);
  373.    }
  374.    d(("ok!\n"));
  375. }
  376. /*E*/
  377.  
  378.    /*
  379.    ** SANA-2 Event management
  380.    */
  381. /*F*/ PRIVATE REGARGS VOID DoEvent(BASEPTR, long event)
  382. {
  383.    struct IOSana2Req *ior, *ior2;
  384.  
  385.    d(("event is %lx\n",event));
  386.  
  387.    ObtainSemaphore(&pb->pb_EventListSem );
  388.    
  389.    for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
  390.        ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
  391.        ior = ior2 )
  392.    {
  393.       if (ior->ios2_WireError & event)
  394.       {
  395.      Remove((struct Node*)ior);
  396.      DevTermIO(pb, ior);
  397.       }
  398.    }
  399.    
  400.    ReleaseSemaphore(&pb->pb_EventListSem );
  401. }
  402. /*E*/
  403.  
  404.    /*
  405.    ** writing packets
  406.    */
  407. /*F*/ PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
  408. {
  409.    BOOL having_line;
  410.    AW_RESULT rc;
  411.    struct PLIPFrame *frame = pb->pb_Frame;
  412.  
  413.    /*
  414.    ** Arbitration
  415.    ** ===========================================================
  416.    **
  417.    ** Pseudo code of the arbitration:
  418.    **
  419.    **  if LINE is high (other side is ready to receive) then
  420.    **     set REQUEST high (tell the other side we're ready to send)
  421.    **     if LINE is high (other side is still ready to receive) then
  422.    **        we have the line, do transfer
  423.    **     reset REQUEST to low (tell other side we're ready to receive)
  424.    **
  425.    **    AW_OK             if we could transmit all the data correctly
  426.    **    AW_BUFF_ERROR     if the BufferManagement callback failed
  427.    **    AW_ERROR          if we got the line, but the actual transfer
  428.    **                      failed, perhaps due to a timeout
  429.    **    AW_ABORT          if we couldn't get the line
  430.    */
  431.  
  432. #ifdef LINPLIP
  433.    having_line = !TESTLINE(pb);
  434.    if(!having_line)
  435.    {
  436.      if (!(pb->pb_Flags & PLIPF_RECEIVING))
  437.         CLEARREQUEST(pb);                         /* reset line state */
  438.      d2(("couldn't get the line\n"));
  439.    }
  440. #else
  441.    having_line = FALSE;
  442.  
  443.    if (!TESTLINE(pb))                               /* is the line free ? */
  444.    {
  445.       SETREQUEST(pb);                     /* indicate our request to send */
  446.       
  447. #if 0
  448.    /*
  449.    ** I have removed again the ARBITRATIONDELAY feature, although I am not
  450.    ** really sure if this is a good thing. Anyway I didn't experience
  451.    ** any more those nasty line errors, that initially made me implementing
  452.    ** this. For now I've left the code here to let you play with it. Please
  453.    ** report any comments concerning this.
  454.    **
  455.    ** In fact the arbitration leaves a small door for undetected, real
  456.    ** collisision, as the request lines are used for handshake during the
  457.    ** transmission process. The CLEARREQUEST after NOT getting the line
  458.    ** could be misinterpreted by the other side as the first handshake. Up
  459.    ** to now I couldn't conceive a satisfying solution for this.
  460.    */
  461.  
  462.       if (pb->pb_ArbitrationDelay > 0)
  463.       {
  464.      pb->pb_CollReq.tr_time.tv_secs    = 0;
  465.      pb->pb_CollReq.tr_time.tv_micro   = pb->pb_ArbitrationDelay;
  466.      pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  467.      DoIO((struct IORequest*)&pb->pb_CollReq);
  468.       }
  469. #endif
  470.  
  471.       if (!TESTLINE(pb))                      /* is the line still free ? */
  472.      having_line = TRUE;
  473.       else
  474.       {
  475.      if (!(pb->pb_Flags & PLIPF_RECEIVING))
  476.         CLEARREQUEST(pb);                         /* reset line state */
  477.      d2(("couldn't get the line-1\n"));
  478.       }
  479.    }
  480.    else d2(("couldn't get the line-2\n"));
  481. #endif /* LINPLIP */
  482.  
  483.    if (having_line)
  484.    {
  485.       struct BufferManagement *bm;
  486.  
  487.       if (!(pb->pb_Flags & PLIPF_RECEIVING))
  488.       {
  489.      d(("having line for: type %08lx, size %ld\n",ios2->ios2_PacketType,
  490.                               ios2->ios2_DataLength));
  491.  
  492.      frame->pf_Type = ios2->ios2_PacketType;
  493.      frame->pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
  494.  
  495.      bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
  496.  
  497.      if (!(*bm->bm_CopyFromBuffer)((UBYTE*)(frame+1),
  498.                      ios2->ios2_Data, ios2->ios2_DataLength))
  499.      {
  500.         rc = AW_BUFFER_ERROR;
  501.         CLEARREQUEST(pb);                         /* reset line state */
  502.      }
  503.      else
  504.      {
  505.         /* wait until I/O block is safe to be reused */
  506.         while(!pb->pb_TimeoutSet) Delay(1L);
  507.         pb->pb_TimeoutReq.tr_time.tv_secs = 0;
  508.         pb->pb_TimeoutReq.tr_time.tv_micro = pb->pb_Timeout;
  509.         pb->pb_TimeoutSet = 0;
  510.         SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  511.         rc = hwsend(pb) ? AW_OK : AW_ERROR;
  512.         AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  513. #if DEBUG&8
  514.         if(rc==AW_ERROR) d8(("Error sending packet (size=%ld)\n", (LONG)pb->pb_Frame->pf_Size));
  515. #endif
  516.      }
  517.       }
  518.       else
  519.       {
  520.      d4(("arbitration error!\n"));
  521.      rc = AW_ABORTED;
  522.       }
  523.    }
  524.    else
  525.       rc = AW_ABORTED;
  526.  
  527.    return rc;
  528. }
  529. /*E*/
  530. /*F*/ PRIVATE REGARGS VOID dowritereqs(BASEPTR)
  531. {
  532.    struct IOSana2Req *currentwrite, *nextwrite;
  533.    AW_RESULT code;
  534.  
  535.    ObtainSemaphore(&pb->pb_WriteListSem);
  536.  
  537.    for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
  538.        nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
  539.        currentwrite = nextwrite )
  540.    {
  541.       if (pb->pb_Flags & PLIPF_RECEIVING)
  542.       {
  543.      d(("incoming data!"));
  544.      break;
  545.       }
  546.  
  547.       code = arbitratedwrite(pb, currentwrite);
  548.  
  549.       if (code == AW_ABORTED)                         /* arbitration failed */
  550.       {
  551.      pb->pb_Flags |= PLIPF_COLLISION;
  552.      d(("couldn't get the line, trying again later\n"));
  553.      pb->pb_SpecialStats[S2SS_COLLISIONS].Count++;
  554.      d(("pb->pb_SpecialStats[S2SS_COLLISIONS].Count = %ld\n",pb->pb_SpecialStats[S2SS_COLLISIONS].Count));
  555.      if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
  556.      {
  557.         pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  558.         d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  559.         currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  560.         currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
  561.         Remove((struct Node*)currentwrite);
  562.         DevTermIO(pb, currentwrite);
  563.      }
  564.      break;
  565.       }
  566.       else if (code == AW_BUFFER_ERROR)  /* BufferManagement callback error */
  567.       {
  568.      d(("buffer error\n"));
  569.      DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  570.      pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  571.      d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  572.      currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
  573.      currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
  574.      Remove((struct Node*)currentwrite);
  575.      DevTermIO(pb, currentwrite);
  576.       }
  577.       else if (code == AW_ERROR)
  578.       {
  579.      /*
  580.      ** this is a real line error, upper levels (e.g. Internet TCP) have
  581.      ** to care for reliability!
  582.      */
  583.      d(("error while transmitting packet\n"));
  584.      DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
  585.      pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  586.      d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  587.      currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  588.      currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  589.      Remove((struct Node*)currentwrite);
  590.      DevTermIO(pb, currentwrite);
  591.       }
  592.       else /*if (code == AW_OK)*/                             /* well done! */
  593.       {
  594.      d(("packet transmitted successfully\n"));
  595.      pb->pb_DevStats.PacketsSent++;
  596.      dotracktype(pb, (ULONG) pb->pb_Frame->pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
  597.      currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
  598.      currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  599.      Remove((struct Node*)currentwrite);
  600.      DevTermIO(pb, currentwrite);
  601.       }
  602.    }
  603.  
  604.    ReleaseSemaphore(&pb->pb_WriteListSem);
  605. }
  606. /*E*/
  607.  
  608.    /*
  609.    ** reading packets
  610.    */
  611. /*F*/ PRIVATE REGARGS VOID doreadreqs(BASEPTR)
  612. {
  613.    LONG datasize;
  614.    struct IOSana2Req *got;
  615.    ULONG pkttyp;
  616.    struct BufferManagement *bm;
  617.    BOOL rv;
  618.    struct PLIPFrame *frame = pb->pb_Frame;
  619.  
  620.    /* wait until I/O block is safe to be reused */
  621.    while(!pb->pb_TimeoutSet) Delay(1L);
  622.    pb->pb_TimeoutReq.tr_time.tv_secs    = 0;
  623.    pb->pb_TimeoutReq.tr_time.tv_micro   = pb->pb_Timeout;
  624.    pb->pb_TimeoutSet = 0;
  625.    SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  626.    rv = hwrecv(pb);
  627.    AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  628.  
  629.    if (rv)
  630.    {
  631.       pb->pb_DevStats.PacketsReceived++;
  632.  
  633.       datasize = frame->pf_Size - PKTFRAMESIZE_2;
  634.  
  635.       dotracktype(pb, pkttyp = frame->pf_Type, 0, 1, 0, datasize, 0);
  636.  
  637.       d(("packet %08lx, size %ld received\n",pkttyp,datasize));
  638.  
  639.       ObtainSemaphore(&pb->pb_ReadListSem);
  640.  
  641.      /* traverse the list of read-requests */
  642.       for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
  643.       got->ios2_Req.io_Message.mn_Node.ln_Succ;
  644.       got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
  645.       {
  646.         /* check if this one requests for the new packet we got */
  647.      if (got->ios2_PacketType == pkttyp )
  648.      {
  649.         Remove((struct Node*)got);
  650.  
  651.         bm = (struct BufferManagement *)got->ios2_BufferManagement;
  652.  
  653.         if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  654.         {
  655.            d(("CopyToBuffer: error\n"));
  656.            got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  657.            got->ios2_WireError = S2WERR_BUFF_ERROR;
  658.            DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  659.         }
  660.         else
  661.         {
  662.            got->ios2_Req.io_Error = got->ios2_WireError = 0;
  663.         }
  664.  
  665.         got->ios2_Req.io_Flags = 0;
  666. #ifndef LINPLIP
  667.         memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  668.         memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  669. #endif
  670.         got->ios2_DataLength = datasize;
  671.  
  672.         d(("packet received, satisfying S2Request\n"));
  673.         DevTermIO(pb, got);
  674.         got = NULL;
  675.         break;
  676.      }
  677.       }
  678.  
  679.       ReleaseSemaphore(&pb->pb_ReadListSem);
  680.    }
  681.    else
  682.    {
  683.       d8(("Error receiving (%ld. len=%ld)\n", rv, frame->pf_Size));
  684.       /* something went wrong during receipt */
  685.       DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
  686.       got = NULL;
  687.       pb->pb_DevStats.BadData++;
  688.    }
  689.  
  690.       /* If no one wanted this packet explicitely, there is one chance
  691.       ** left: somebody waiting for orphaned packets. If this fails, too,
  692.       ** we will drop it.
  693.       */
  694.    if (got)
  695.    {
  696.       d(("unknown packet\n"));
  697.  
  698.       pb->pb_DevStats.UnknownTypesReceived++;
  699.       
  700.       ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  701.       got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
  702.       ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  703.  
  704.       if (got)
  705.       {
  706.      bm = (struct BufferManagement *)got->ios2_BufferManagement;
  707.      if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  708.      {
  709.         got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  710.         got->ios2_WireError = S2WERR_BUFF_ERROR;
  711.      }
  712.      else
  713.      {
  714.         got->ios2_Req.io_Error = got->ios2_WireError = 0;
  715.      }
  716.      
  717.      got->ios2_Req.io_Flags = 0;
  718. #ifndef LINPLIP
  719.      memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  720.      memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  721. #endif
  722.      got->ios2_DataLength = datasize;
  723.  
  724.      d(("orphan read\n"));
  725.  
  726.      DevTermIO(pb, got);
  727.       }
  728.       else
  729.       {
  730.      dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
  731.      d(("packet thrown away...\n"));
  732.       }
  733.    }
  734. }
  735. /*E*/
  736.  
  737.    /*
  738.    ** 2nd level device command dispatcher (~SANA2IOF_QUICK)
  739.    */
  740. /*F*/ PRIVATE REGARGS VOID dos2reqs(BASEPTR)
  741. {
  742.    struct IOSana2Req *ios2;
  743.  
  744.    /*
  745.    ** Every pending IO message will be GetMsg()'ed and processed. At the
  746.    ** end of the loop it will be DevTermIO()'ed back to the sender,
  747.    ** _but_only_if_ it is non-NULL. In such cases the message has been
  748.    ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
  749.    ** and similar stuff).
  750.    ** You find the same mimique in the 1st level dispatcher (device.c)
  751.    */
  752.    while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
  753.    {
  754.       if (pb->pb_Flags & PLIPF_RECEIVING)
  755.       {
  756.      d(("incoming data!"));
  757.      break;
  758.       }
  759.  
  760.       d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
  761.  
  762.       switch (ios2->ios2_Req.io_Command)
  763.       {
  764.      case S2_ONLINE:
  765.         if (!goonline(pb))
  766.         {
  767.            ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  768.            ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  769.         }
  770.      break;
  771.  
  772.      case S2_OFFLINE:
  773.         gooffline(pb);
  774.         rejectpackets(pb); /* reject all pending requests */
  775.      break;
  776.  
  777.      case S2_CONFIGINTERFACE:
  778.         if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
  779.         {
  780. #ifndef LINPLIP
  781.            memcpy(ios2->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  782.            memcpy(ios2->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  783. #endif
  784.            if (!goonline(pb))
  785.            {
  786.           ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  787.           ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  788.            }
  789.         }
  790.         else
  791.         {
  792.            ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  793.            ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  794.         }
  795.      break;
  796.       }
  797.  
  798.       if (ios2) DevTermIO(pb,ios2);
  799.    }
  800. }
  801. /*E*/
  802.  
  803.    /*
  804.    ** startup,initialisation and termination functions
  805.    */
  806. /*F*/ PRIVATE struct PLIPBase *startup(void)
  807. {
  808.    struct ServerStartup *ss;
  809.    struct Process *we;
  810.    struct PLIPBase *base;
  811.    LOCALSYSBASE;
  812.  
  813.    we = (struct Process*)FindTask(NULL);
  814.  
  815.    d(("waiting for startup msg...\n"));
  816.    WaitPort(&we->pr_MsgPort);
  817.    ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
  818.    base = ss->ss_PLIPBase;
  819.    base->pb_Startup = ss;
  820.    d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
  821.  
  822.    /* we will keep the startup message, to inform mother if we
  823.    ** really could come up or if we failed to obtain some
  824.    ** resource.
  825.    */
  826.    return base;
  827. }
  828. /*E*/
  829. /*F*/ PRIVATE VOID readargs(BASEPTR)
  830. {
  831.    struct RDArgs *rda;
  832.    struct PLIPConfig args = { 0 };
  833.    BPTR plipvar, oldinput;
  834.  
  835.    d(("entered\n"));
  836.  
  837.    if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
  838.    {
  839.       oldinput = SelectInput(plipvar);
  840.       
  841.       rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
  842.       
  843.       if(rda)
  844.       {
  845.      if (args.timeout)
  846.         pb->pb_Timeout =
  847.           BOUNDS(*args.timeout, PLIP_MINTIMEOUT, PLIP_MAXTIMEOUT);
  848.  
  849.      if (args.priority)
  850.         SetTaskPri((struct Task*)pb->pb_Server,
  851.           BOUNDS(*args.priority, PLIP_MINPRIORITY, PLIP_MAXPRIORITY));
  852.  
  853.      if (args.mtu)
  854.         pb->pb_MTU = BOUNDS(*args.mtu, PLIP_MINMTU, PLIP_MAXMTU);
  855.  
  856.      if (args.bps)
  857.         pb->pb_ReportBPS = BOUNDS(*args.bps, PLIP_MINBPS, PLIP_MAXBPS);
  858.  
  859.      if (args.retries)
  860.         pb->pb_Retries =
  861.              BOUNDS(*args.retries, PLIP_MINRETRIES, PLIP_MAXRETRIES);
  862.  
  863.      if (args.sendcrc)
  864.         pb->pb_Flags |= PLIPF_SENDCRC;
  865.       else
  866.         pb->pb_Flags &= ~PLIPF_SENDCRC;
  867.  
  868.      if (args.collisiondelay)
  869.         pb->pb_CollisionDelay =
  870.            BOUNDS(*args.collisiondelay, PLIP_MINCOLLISIONDELAY,
  871.                         PLIP_MAXCOLLISIONDELAY);
  872.      else
  873.         pb->pb_CollisionDelay = PLIP_DEFDELAY + (pb->pb_Unit ?
  874.                           PLIP_DELAYDIFF : 0);
  875.  
  876.      if (args.arbitrationdelay)
  877.         pb->pb_ArbitrationDelay =
  878.            BOUNDS(*args.collisiondelay, PLIP_MINARBITRATIONDELAY,
  879.                         PLIP_MAXARBITRATIONDELAY);
  880.      else
  881.         pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
  882.  
  883.      if (args.nospecialstats)
  884.         pb->pb_ExtFlags |= PLIPEF_NOSPECIALSTATS;
  885.  
  886.      FreeArgs(rda);
  887.       }
  888.  
  889.       Close(SelectInput(oldinput));
  890.    }
  891.  
  892.    d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
  893.       pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
  894.       pb->pb_Flags, pb->pb_CollisionDelay));
  895.  
  896.    d(("left\n"));
  897.  
  898. }
  899. /*E*/
  900. /*F*/ PRIVATE BOOL init(BASEPTR)
  901. {
  902.    BOOL rc = FALSE;
  903.    ULONG sigmask;
  904.  
  905.    if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
  906.    {
  907.       pb->pb_IntSigMask = 1L << pb->pb_IntSig;
  908.    
  909.       if ((pb->pb_ServerPort = CreateMsgPort()))
  910.       {
  911.      if ((pb->pb_CollPort = CreateMsgPort()))
  912.      {
  913.         if ((pb->pb_TimeoutPort = CreateMsgPort()))
  914.         {
  915.            /* save old exception setup */
  916.            pb->pb_OldExcept = SetExcept(0, 0xffffffff); /* turn'em off */
  917.            pb->pb_OldExceptCode = pb->pb_Server->pr_Task.tc_ExceptCode;
  918.            pb->pb_OldExceptData = pb->pb_Server->pr_Task.tc_ExceptData;
  919.  
  920.            /* create new exception setup */
  921.            pb->pb_Server->pr_Task.tc_ExceptCode = (APTR)&exceptcode;
  922.            pb->pb_Server->pr_Task.tc_ExceptData = (APTR)pb;
  923.            SetSignal(0, sigmask = (1 << pb->pb_TimeoutPort->mp_SigBit));
  924.            SetExcept(sigmask, sigmask);
  925.  
  926.            /* enter port address */
  927.            pb->pb_CollReq.tr_node.io_Message.mn_ReplyPort = pb->pb_CollPort;
  928.            if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_CollReq, 0))
  929.            {
  930.           TimerBase = (struct Library *)pb->pb_CollReq.tr_node.io_Device;
  931.  
  932.           /* preset the io command, this will never change */
  933.           pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  934.  
  935.           /* setup the timeout stuff */
  936.           pb->pb_TimeoutReq.tr_node.io_Flags = IOF_QUICK;
  937.           pb->pb_TimeoutReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimeoutPort;
  938.           pb->pb_TimeoutReq.tr_node.io_Device = pb->pb_CollReq.tr_node.io_Device;
  939.           pb->pb_TimeoutReq.tr_node.io_Unit = pb->pb_CollReq.tr_node.io_Unit;
  940.           pb->pb_TimeoutReq.tr_node.io_Command = TR_ADDREQUEST;
  941.           pb->pb_TimeoutSet = 0xff;
  942.  
  943.           readargs(pb);
  944.           d(("allocating 0x%lx/%ld bytes frame buffer\n",
  945.                        sizeof(struct PLIPFrame)+pb->pb_MTU,
  946.                        sizeof(struct PLIPFrame)+pb->pb_MTU));
  947.           if ((pb->pb_Frame = AllocVec((ULONG)sizeof(struct PLIPFrame) +
  948.                           pb->pb_MTU, MEMF_CLEAR|MEMF_ANY)))
  949.           {
  950.              rc = TRUE;
  951.           }
  952.           else
  953.           {
  954.              d(("couldn't allocate frame buffer\n"));
  955.           }
  956.            }
  957.            else
  958.            {
  959.           d(("couldn't open timer.device"));
  960.            }
  961.         }
  962.         else
  963.         {
  964.            d(("no port for timeout handling\n"));
  965.         }
  966.      }
  967.      else
  968.      {
  969.         d(("no port for collision handling\n"));
  970.      }
  971.       }
  972.       else
  973.       {
  974.      d(("no server port\n"));
  975.       }
  976.    }
  977.    else
  978.    {
  979.       d(("no signal\n",rc));
  980.    }
  981.  
  982.    d(("left %ld\n",rc));
  983.  
  984.    return rc;
  985. }
  986. /*E*/
  987. /*F*/ PRIVATE VOID cleanup(BASEPTR)
  988. {
  989.    struct BufferManagement *bm;
  990.  
  991.    gooffline(pb);
  992.  
  993.    while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
  994.       FreeVec(bm);
  995.  
  996.    if (pb->pb_Frame) FreeVec(pb->pb_Frame);
  997.  
  998.    if (pb->pb_TimeoutPort)
  999.    {
  1000.       /* restore old exception setup */
  1001.       SetExcept(0, 0xffffffff);    /* turn'em off */
  1002.       pb->pb_Server->pr_Task.tc_ExceptCode = pb->pb_OldExceptCode;
  1003.       pb->pb_Server->pr_Task.tc_ExceptData = pb->pb_OldExceptData;
  1004.       SetExcept(pb->pb_OldExcept, 0xffffffff);
  1005.  
  1006.       if (TimerBase)
  1007.       {
  1008.      WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  1009.      CloseDevice((struct IORequest*)&pb->pb_CollReq);
  1010.       }
  1011.       DeleteMsgPort(pb->pb_TimeoutPort);
  1012.    }
  1013.    if (pb->pb_CollPort) DeleteMsgPort(pb->pb_CollPort);
  1014.  
  1015.    if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
  1016.    if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
  1017.  
  1018.    if (pb->pb_Flags & PLIPF_REPLYSS)
  1019.    {
  1020.       Forbid();
  1021.       ReplyMsg((struct Message*)pb->pb_Startup);
  1022.    }
  1023. }
  1024. /*E*/
  1025.  
  1026.    /*
  1027.    ** entry point, mainloop
  1028.    */
  1029. /*F*/ PUBLIC VOID SAVEDS ServerTask(void)
  1030. {
  1031.    BASEPTR;
  1032.  
  1033.    d(("server running\n"));
  1034.  
  1035.    if (pb = startup())
  1036.    {
  1037.      /* if we fail to allocate all resources, this flag reminds cleanup()
  1038.      ** to ReplyMsg() the startup message
  1039.      */
  1040.       pb->pb_Flags |= PLIPF_REPLYSS;
  1041.  
  1042.       if (init(pb))
  1043.       {
  1044.      ULONG recv=0, portsigmask, timersigmask, wmask;
  1045.      BOOL running, timerqueued = FALSE;
  1046.  
  1047.      /* Ok, we are fine and will tell this mother personally :-) */
  1048.      pb->pb_Startup->ss_Error = 0;
  1049.      /* don't forget this, or we will have to keep a warm place */
  1050.      /* in our coffin for the system */
  1051.      pb->pb_Flags &= ~PLIPF_REPLYSS;
  1052.      ReplyMsg((struct Message*)pb->pb_Startup);
  1053.  
  1054.      portsigmask  = 1 << pb->pb_ServerPort->mp_SigBit;
  1055.      timersigmask = 1 << pb->pb_CollPort->mp_SigBit;
  1056.       
  1057.      wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
  1058.  
  1059.      for(running=TRUE;running;)
  1060.      {
  1061.         d(("wmask is 0x%08lx\n", wmask));
  1062.  
  1063.         if (!(pb->pb_Flags & PLIPF_RECEIVING))
  1064.            recv = Wait(wmask);
  1065.         else
  1066.            SetSignal(0, pb->pb_IntSigMask);
  1067.  
  1068.         /*if (recv & pb->pb_IntSigMask)*/
  1069.         if (pb->pb_Flags & PLIPF_RECEIVING)
  1070.         {
  1071.            d(("received an interrupt\n"));
  1072.            doreadreqs(pb);
  1073.         }
  1074.  
  1075.         if (recv & portsigmask)
  1076.         {
  1077.            d(("SANA-II request(s)\n"));
  1078.            dos2reqs(pb);
  1079.         }
  1080.  
  1081.         if (recv & timersigmask)
  1082.         {
  1083.            /* pop message */
  1084.            AbortIO((struct IORequest*)&pb->pb_CollReq);
  1085.            WaitIO((struct IORequest*)&pb->pb_CollReq);
  1086.            timerqueued = FALSE;
  1087.            d(("timer wakeup\n"));
  1088.         }
  1089.  
  1090.            /* try now to do write requests (if any pending) */
  1091.         if (!timerqueued)
  1092.         {
  1093.            dowritereqs(pb);
  1094.  
  1095.           /* don't let the other side wait too long! */
  1096.            if (pb->pb_Flags & PLIPF_RECEIVING)
  1097.            {
  1098.           d(("received an interrupt\n"));
  1099.           SetSignal(0, pb->pb_IntSigMask);
  1100.           doreadreqs(pb);
  1101.            }
  1102.  
  1103.            /*
  1104.            ** Possible a collision has occurred, which is indicated by a
  1105.            ** special flag in PLIPBase.
  1106.            **
  1107.            ** Using timer.device we periodically will be waked up. This
  1108.            ** allows us to delay write packets in cases when we cannot get
  1109.            ** the line immediately.
  1110.            **
  1111.            ** If client and server are very close together, regarding the point
  1112.            ** of performance, the same delay time could even force multiple
  1113.            ** collisions (at least theoretical, I made no practical tests).
  1114.            ** Probably a CSMA/CD-like random-timed delay would be ideal.
  1115.            */
  1116.            if (pb->pb_Flags & PLIPF_COLLISION)
  1117.            {
  1118.           pb->pb_Flags &= ~PLIPF_COLLISION;
  1119.           pb->pb_CollReq.tr_time.tv_secs    = 0;
  1120.           pb->pb_CollReq.tr_time.tv_micro   = pb->pb_CollisionDelay;
  1121.           SendIO((struct IORequest*)&pb->pb_CollReq);
  1122.           timerqueued = TRUE;
  1123.            }
  1124.         }
  1125.  
  1126.         if (recv & SIGBREAKF_CTRL_C)
  1127.         {
  1128.            d(("received break signal\n"));
  1129.            running = FALSE;
  1130.         }
  1131.      }
  1132.  
  1133.      if (timerqueued)
  1134.      {
  1135.            /* finnish pending timer requests */
  1136.         AbortIO((struct IORequest*)&pb->pb_CollReq);
  1137.         WaitIO((struct IORequest*)&pb->pb_CollReq);
  1138.      }
  1139.       }
  1140.       else
  1141.      d(("init() failed\n"));
  1142.  
  1143.       d(("cleaning up\n"));
  1144.       cleanup(pb);
  1145.  
  1146.         /* Exec will enable it's scheduler after we're dead. */
  1147.       Forbid();
  1148.         /* signal mother we're done */
  1149.       if (pb->pb_ServerStoppedSigMask)
  1150.      Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
  1151.       pb->pb_Flags |= PLIPF_SERVERSTOPPED;
  1152.    }
  1153.    else
  1154.       d(("no startup packet\n"));
  1155. }
  1156. /*E*/
  1157.  
  1158.